
package full_search;

import agents.FullAgent;
import env.Action;
import env.Enviroment;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 
 * Full search searches for a solution for the entire board, and not just 1 flag.
 * TODO : make this work.
 * @author user
 */
public abstract class FullSearch {

    LinkedList<Action> plan = null;
    private FullAgent agent;
    public int expanded_nodes=0; //"T"
    //int iterations

    public abstract LinkedList<Action> search();
    
    public boolean goalTest(FullNode n) {
        return n.remainingFlags()==0 || !n.getState().isAlive;
    }
    
    /**
     * a generic search, just plug in a queueing function and you're golden!
     * @param queue
     * @return
     */
    public LinkedList<Action> graphSearch(MyQueue queue) {
        HashSet<FullNode> closed = new HashSet<FullNode>();
        FullNode root=new FullNode(null, null, 0, 0, new FullState(agent.getRow(), agent.getCol(), agent.getOrientation(), Enviroment.env.flags, Enviroment.env.getSentry(), agent.isAlive()));
        if(goalTest(root)) {
            System.out.println("i'm Already at a goal state: no search is required!");
            return null;
        }
        queue.add(root);
        closed.add(root);
        int c = 0, e=0;
        while (!queue.isEmpty()) {
            FullNode node = queue.poll();
            //System.out.print("exapnding "+node+" [ ");
            // _ goal test _
            if (goalTest(node)) {
                System.out.println("@@@@ after " + c + " iteration, search is finished with "+node);
                //Enviroment.env.drawArrow(getAgent().getRow(), getAgent().getCol(), node.getRow(), node.getCol(), agent.getColor());
                expanded_nodes+=e;
                return node.getActionPath();
            }
            List<FullNode> expand = node.expand();
            int q=0;
            for (FullNode n : expand) {
                if (!closed.contains(n)) {
                    queue.add(n);
                    closed.add(n);
                    e++;
                    q++;
                   // System.out.print ("#"+n.id+", ");
                }
            }
           // System.out.println("]  - total "+q+" new nodes");
            c++;
            
        }
    System.out.println("@@@@ after " + c + " iteration, search is NULL! @@@@"); 
        return null;
    }
    
    
    
        /**
     * a generic search, just plug in a queueing function and you're golden!
     * @param queue
     * @return
     */
//    public LinkedList<Action> treeSearch(MyQueue queue) {
//        queue.add(new FullNode(null, null, 0, 0, agent.getState()));
//        int c = 0, e=0;
//        while (!queue.isEmpty()) {
//            FullNode node = queue.poll();
//            //System.out.print("exapnding node "+node);
//            // _ goal test _
//            if (node.remainingFlags()==0) {
//                System.out.println("@@@@ after " + c + " iteration, search is finished! @@@@");
//                //Enviroment.env.drawArrow(getAgent().getRow(), getAgent().getCol(), node.getRow(), node.getCol(), agent.getColor());
//                expanded_nodes+=e;
//                return node.getActionPath();
//            }
//            List<FullNode> expand = node.expand();
//            //System.out.println("");
//            for (FullNode n : expand) {
//                    queue.add(n);
//                    e++;
//            }
//            c++;
//        }
//    System.out.println("@@@@ after " + c + " iteration, search is NULL! @@@@"); 
//        return null;
//    }

    public Action nextAction() {
        if (plan == null || plan.isEmpty()) {
            rePlan();
        }
        if (plan == null || plan.isEmpty()) {
            return null;
        }
        return plan.removeFirst();
    }

    public void rePlan() {
        try {
            Thread.sleep(50);
        } catch (InterruptedException ex) {
            Logger.getLogger(FullSearch.class.getName()).log(Level.SEVERE, null, ex);
        }
        System.out.println("before replanning, my performance measure is " + Enviroment.f+"*"+agent.score+" - "+expanded_nodes+" = "+((Enviroment.f * agent.score) - expanded_nodes));
        //FullBFS : before replanning, my performance measure is 10*183 - 194133 = -192303

        long start=System.currentTimeMillis();
        plan = search();
        long finish=System.currentTimeMillis();
        
        if(plan!=null)
            System.out.println("my new plan |"+plan.size()+"| is " + plan);
        else
            System.out.println("i couldn't come up with a plan :(");
        System.out.println("planning time=" + (finish-start));
        System.exit(0);
        try {
            System.out.println("press enter to confirm!");
            System.in.read();
        } catch (IOException ex) {
            Logger.getLogger(FullSearch.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        
    }

    public FullAgent getAgent() {
        return agent;
    }

    public void setAgent(FullAgent agent) {
        this.agent = agent;
    }
}
